package lifeOfAFish.scenegraph.test;


import lifeOfAFish.test.JoglTemplate;
import java.io.File;

import javax.media.opengl.*;
//import javax.media.opengl.GLAutoDrawable;

import com.sun.opengl.cg.CGcontext;
import com.sun.opengl.cg.CGparameter;
import com.sun.opengl.cg.CGprogram;
import com.sun.opengl.cg.CgGL;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
import lifeOfAFish.scenegraph.*;
import lifeOfAFish.scenegraph.geom.*;


public class test_waterSurface extends JoglTemplate {
	protected static final String FRAGMENT_SHADER = "shader/fp_phongPerPixel.cg";

	protected static final String VERTEX_SHADER = "shader/vp_waves.cg";

	static final float[] BRASS_MATERIAL = { 0.33f, 0.22f, 0.03f, 1.0f, 0.78f,
			0.57f, 0.11f, 1.0f, 0.99f, 0.91f, 0.81f, 1.0f, 5.0f };

	static final float[] REDPLASTIC_MATERIAL = { 0.3f, 0.0f, 0.0f, 1.0f, 0.6f,
			0.0f, 0.0f, 1.0f, 0.8f, 0.4f, 0.4f, 1.0f, 10.0f };

	static final float[] WHITESHINEY_MATERIAL = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
			1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 100.0f };

	static final float[][] MATERIALS = { BRASS_MATERIAL, REDPLASTIC_MATERIAL,
			WHITESHINEY_MATERIAL };

	static final float[] MOVING_LIGHT_ADS = { 0.2f, 0.2f, 0.2f, 1f, 0.95f, 0.95f,
			0.95f, 1f, 0.95f, 0.95f, 0.95f, 1f };

	private CGcontext cgContext;
	private CGprogram cgVertexProg = null, cgFragmentProg = null;
	private CGparameter cgModelViewProj, cgModelViewInv;
	private CGparameter cgIa, cgId, cgIs, cgKs, cgKd, cgKa, cgShininess;
	private CGparameter cgEyePosition, cgLightPosition;
	private CGparameter cgStretch; 
	private CGparameter cgWave; 
	private int cgVertexProfile, cgFragProfile;

	protected int dList;
	private int frameCounter = Integer.MIN_VALUE;
	private int currentMaterial = 0;
	private boolean stretch = false, animation = true;
	
	
	// scenegraph nodes
	sgNode root = new sgNode();
	sgGeomWaterSurface surf = null;
	sgLight light = null;
	
	sgTransform rot = new sgTransform();
	sgTransform trans = new sgTransform();
	
	
	float theta = 0.0f;
	float theta2 = 0.0f;
	float step = 1.0f;
	
	
	
	
	
	public static void main (String[] args){
		test_waterSurface template = new test_waterSurface();
		template.setVisible(true);
		
	}
	
	public void initCg()
	{
		cgContext = CgGL.cgCreateContext();
		cgVertexProfile = CgGL.cgGLGetLatestProfile(CgGL.CG_GL_VERTEX);
		if (cgVertexProfile == CgGL.CG_PROFILE_UNKNOWN)
		{
			System.err.println("Invalid vertex profile");
			System.exit(1);
		}
		CgGL.cgGLSetOptimalOptions(cgVertexProfile);

		cgFragProfile = CgGL.cgGLGetLatestProfile(CgGL.CG_GL_FRAGMENT);
		if (cgFragProfile == CgGL.CG_PROFILE_UNKNOWN)
		{
			System.err.println("Invalid fragment profile");
			System.exit(1);
		}
		CgGL.cgGLSetOptimalOptions(cgFragProfile);
	}

	public CGprogram loadShader(int profile, String filename)
	{
		CGprogram shaderprog = CgGL.cgCreateProgramFromFile(getCgContext(),
				CgGL.CG_SOURCE, filename, profile, null, null);
		if (shaderprog == null)
		{
			int err = CgGL.cgGetError();
			System.err.println("Compile shader [" + filename + "] "
					+ CgGL.cgGetErrorString(err));
			if (CgGL.cgGetLastListing(getCgContext()) != null)
			{
				System.err.println(CgGL.cgGetLastListing(getCgContext()) + "\n");
			}
			System.exit(1);
		}

		CgGL.cgGLLoadProgram(shaderprog);

		int err = CgGL.cgGetError();
		if (err != CgGL.CG_NO_ERROR)
		{
			System.out.println("Load shader [" + filename + "]: "
					+ CgGL.cgGetErrorString(err));
			System.exit(1);
		}

		return shaderprog;
	}

	protected void bindParameters()
	{
		cgIa = CgGL.cgGetNamedParameter(cgFragmentProg, "Ia");
		cgId = CgGL.cgGetNamedParameter(cgFragmentProg, "Id");
		cgIs = CgGL.cgGetNamedParameter(cgFragmentProg, "Is");
		cgKa = CgGL.cgGetNamedParameter(cgFragmentProg, "Ka");
		cgKd = CgGL.cgGetNamedParameter(cgFragmentProg, "Kd");
		cgKs = CgGL.cgGetNamedParameter(cgFragmentProg, "Ks");
		cgShininess = CgGL.cgGetNamedParameter(cgFragmentProg, "shininess");
		cgLightPosition = CgGL.cgGetNamedParameter(cgFragmentProg, "lightPosition");
		cgEyePosition = CgGL.cgGetNamedParameter(cgFragmentProg, "eyePosition");
		cgModelViewProj = CgGL.cgGetNamedParameter(cgVertexProg, "modelViewProj");
		cgModelViewInv = CgGL.cgGetNamedParameter(cgFragmentProg, "modelViewInv");
		
		cgWave = CgGL.cgGetNamedParameter(cgVertexProg, "vIn.wave");
		cgStretch = CgGL.cgGetNamedParameter(cgVertexProg, "stretch");
		// TODO: Assignment 3_1: bind stretch factor
	}
	

	public void init(GLAutoDrawable drawable)
	{
		super.init(drawable);
		
		// get gl object
		GL gl = drawable.getGL();
		sgGlobals.gl = gl;
		com.loader.glWrapper.gl = gl;
		
		
		// init Cg
		initCg();
		// load and compile shader
		cgVertexProg = loadShader(getCgVertexProfile(), VERTEX_SHADER);
		cgFragmentProg = loadShader(getCgFragProfile(), FRAGMENT_SHADER);
		// bind CGParameters to vertex and fragment program
		bindParameters();
		
		
		// enable depth testing
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthRange(0.0, 1000.0);
		
		// enable lighting
		gl.glEnable(GL.GL_LIGHTING);
		gl.glShadeModel(GL.GL_PHONG_WIN);
		gl.glEnable(GL.GL_TEXTURE_2D);
		
		gl.glEnable(GL.GL_TEXTURE_2D);
//		gl.glEnable(GL.GL_COLOR_MATERIAL);
//		gl.glEnable(GL.GL_BLEND);
//		gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA);
//		gl.glLightModeli(GL.GL_LIGHT_MODEL_COLOR_CONTROL, GL.GL_SEPARATE_SPECULAR_COLOR);
		
		// construct the scenegraph tree.
//		float s = 0.045f;
		light = sgLightFactory.newLight();
		
		root.addChild(rot);
		rot.addChild(trans);
		trans.translate(2.0f, 1.0f, 0.0f);
		trans.addChild(light);
		
		
		sgGeomSphere sphere = new sgGeomSphere(0.25f);
		
		sgMaterial sphereMat = new sgMaterial();
		sphereMat.setAmbient(1.0f, 1.0f, 1.0f, 1.0f);
		sphereMat.setDiffuse(1.0f, 1.0f, 1.0f, 1.0f);
		sphereMat.setSpecular(1.0f, 1.0f, 1.0f, 1.0f);
		sphereMat.setEmission(1.0f, 1.0f, 1.0f, 1.0f);
		light.getPosition()[3] = 0.0f;
		sphere.setMaterial(sphereMat);
		System.out.println("sphereMat : " + sphereMat);
		light.addChild(sphere);
//		light.setSpotCutoff(20.0f);
		
//		surf = new sgGeomWaterSurface(0.0f, 100.0f, 0.0f, 100.0f);
//		surf.setCGMod(cgWave);
//		surf.setCGModelView(this.cgModelViewProj); 
//		surf.setRes(50.0f);
//		sgTransform surfTrans = new sgTransform();
//		surfTrans.translate(-5.0f, 0.0f, -5.0f);
//		surfTrans.addChild(surf);
//		root.addChild(surfTrans);
		
	}
	
	
	/*
	 * overwritten version of display
	 */
	public void display(GLAutoDrawable drawable)
	{
		// get the gl object
		GL gl = drawable.getGL();
		// set the erasing color (black)
		gl.glClearColor(0f, 0f, 0f, 0f);
		// clear screen with the defined erasing color and depth buffer
		
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glPushMatrix();
		applyMouseTranslation(gl);
		applyMouseRotation(gl);
		
		theta += step;
		rot.rotate(theta, 0.0f, 1.0f, 0.0f);
		
		System.out.println(light.getGlobalCoords());
		
		CgGL.cgSetParameter1f(cgStretch, 0.0f);
		
		// set material for cg
		float[] material = MATERIALS[currentMaterial];
		CgGL.cgSetParameter3fv(cgKa, material, 0);
		CgGL.cgSetParameter3fv(cgKd, material, 4);
		CgGL.cgSetParameter3fv(cgKs, material, 8);
		CgGL.cgSetParameter1fv(cgShininess, material, 12);

		// eyePosition for cg
		float[] eyePosition = new float[] { -getView_transx(), -getView_transy(),
				-getView_transz(), 1f };
		CgGL.cgGLSetParameter3fv(cgEyePosition, eyePosition, 0);

		// set light properties
		CgGL.cgGLSetParameter3fv(cgIa, MOVING_LIGHT_ADS, 0);
		CgGL.cgGLSetParameter3fv(cgId, MOVING_LIGHT_ADS, 4);
		CgGL.cgGLSetParameter3fv(cgIs, MOVING_LIGHT_ADS, 8);

		// calculate light position
		sgVec3 offset = new sgVec3(2.0f, 0.0f, 2.0f);
		float[] lightPos = (sgVec3.add(offset, light.getGlobalCoords())).getV();
		CgGL.cgGLSetParameter3fv(cgLightPosition, lightPos, 0);
		
		CgGL.cgGLSetStateMatrixParameter(cgModelViewProj,
				CgGL.CG_GL_MODELVIEW_PROJECTION_MATRIX, CgGL.CG_GL_MATRIX_IDENTITY);
		CgGL.cgGLSetStateMatrixParameter(cgModelViewInv,
				CgGL.CG_GL_MODELVIEW_MATRIX, CgGL.CG_GL_MATRIX_INVERSE);

		// enable profiles, bind shaders
		CgGL.cgGLEnableProfile(getCgVertexProfile());
		CgGL.cgGLBindProgram(cgVertexProg);
		CgGL.cgGLEnableProfile(getCgFragProfile());
		CgGL.cgGLBindProgram(cgFragmentProg);
		
		// fire the traversal
		root.traverse();
		draw();
		
		// disable profiles, unload shaders
		CgGL.cgGLDisableProfile(getCgVertexProfile());
		CgGL.cgGLDisableProfile(getCgFragProfile());
		
//		draw();
//		
//		root.traverse();

		
		// delay for a while
//		double time = System.currentTimeMillis();
//		while (System.currentTimeMillis() - time < 80);
		
		
		// load an object using the mesh loader
		gl.glPopMatrix();
	}
	
	float wave_movement = 0.0f;
	void draw()
	{
		float[] m_points = {0.0f, 10.0f, 0.0f, 10.0f};
		float m_res = 100;
		GL gl = sgGlobals.gl;
		

		
		gl.glBegin(GL.GL_QUADS);
		float x = m_points[0];
		float width = m_points[1]-m_points[0];
		float sx = width/m_res;
		for(;x < m_points[0]+width; x += sx){
			float y = m_points[2];
			float height = m_points[3]-m_points[2];
			float sy = height/m_res; 
			for(;y < m_points[2]+height; y += sy){
				float h = (float)Math.random();
				
				CgGL.cgGLSetParameter3f(cgWave, wave_movement, 1.0f, 1.0f);
				
				gl.glVertex3f(x, 0.0f, y);
				gl.glVertex3f(x+sx, 0.0f, y);
				gl.glVertex3f(x+sx, 0.0f, y+sy);
				gl.glVertex3f(x, 0.0f, y+sy);
				
				wave_movement += 0.0000005f;
				
				if (wave_movement > 2*Math.PI)									// Prevent Crashing
					wave_movement = 0.0f;
				
//				System.out.println(wave_movement);
				
			}
			
		}
		gl.glEnd();
	}
	
	public int getCgVertexProfile()
	{
		return cgVertexProfile;
	}

	public int getCgFragProfile()
	{
		return cgFragProfile;
	}

	public CGprogram getCgVertexProg()
	{
		return cgVertexProg;
	}

	public void setCgVertexProg(CGprogram cgVertexProg)
	{
		this.cgVertexProg = cgVertexProg;
	}

	public CGprogram getCgFragmentProg()
	{
		return cgFragmentProg;
	}

	public void setCgFragmentProg(CGprogram cgFragmentProg)
	{
		this.cgFragmentProg = cgFragmentProg;
	}

	public CGcontext getCgContext()
	{
		return cgContext;
	}

	public int getFrameCounter()
	{
		return frameCounter;
	}
	
}
